
#include <sdk/sdk.h>
#include <sdk/stats.h>
#include <iostream>
#include <cstdio>
using namespace std;
string fromPercent(double x){
    char *st = new char[100];
    sprintf(st, "%d\\%%", int(x * 100));
    return st;
}
int main(){
freopen("../doc/doc.md", "w", stdout);
cout << R"V0G0N(
# Omnium 规则文档

[TOC]

## 逻辑更新日志

### 3月31日紧急更新

#### SDK

* 修正了一处解析事件时可能导致解析失败与AI跳出的bug。
* 修正了一处头文件错误

### 3月30日更新

#### SDK

* SDK现在可以读取上回合对手做出的所有行动了，存储于`PPlayerInfo::events`中。
* 合并了 robotType 与 RobotType
* 修正了SDK中若干错误的包含关系。
* 修正了样例AI中的设计错误。

#### 修复

* 修正了一个在连接时的判断错误在MSVC环境下造成的逻辑崩溃。
* 修正了一个由于浮点数运算误差导致不同环境下结果不匹配的问题。
* 修正了采集范围设置不正确导致采集范围实际大于预期的问题。
* 修正了链接操作的结算顺序错误。
* 修正了庇护技能有消耗的错误。

#### 游戏性

* 调整了升级的需求和属性的`Exp`，降低了等级之间的差异。
* `levelBias`被提升
* 刚分裂的机器人现在具有能量。
* 降低了空投与链接的延迟
* 增加了防御公式的防御基础数值，降低了防御力的效果。

## 概述

在本文档中，所有这种 `Like_this` 字体的文字，表示一个文件名，或表示你能在SDK中找到并使用的一个关键字。如果它是一个数值，你可以在`const.h`中找到它的值（在没有其他说明的情况下）。

### 地图、游戏目标

游戏在一个正方形的网格地图上进行，地图的大小为)V0G0N";
cout << "$" << MAP_SIZE << "$" << "(`MAP_SIZE`)" << R"V0G0N( $\times$ )V0G0N";
cout << "$" << MAP_SIZE << "$" << "(`MAP_SIZE`)" << R"V0G0N(。地图的每个格子是空地或障碍物，其定义见`MAP`。

游戏双方将各控制若干机器人进行生产与对战。玩家只能在空地上建造机器人。初始时，双方在地图的两个接近对角的位置（()V0G0N";
cout << "$" << TEAM1_POS_X << "$" << "(`TEAM1_POS_X`)" << R"V0G0N(,)V0G0N";
cout << "$" << TEAM1_POS_Y << "$" << "(`TEAM1_POS_Y`)" << R"V0G0N()与()V0G0N";
cout << "$" << TEAM2_POS_X << "$" << "(`TEAM2_POS_X`)" << R"V0G0N(,)V0G0N";
cout << "$" << TEAM2_POS_Y << "$" << "(`TEAM2_POS_Y`)" << R"V0G0N()）各拥有一个机器人。

如果某个玩家消灭了对方所有的机器人，则该玩家获得胜利。如果)V0G0N";
cout << "$" << MAX_ROUND << "$" << "(`MAX_ROUND`)" << R"V0G0N(回合后没有分出胜负，则系统将会根据局面信息计算出优势方，判定其获胜。（具体方法之后会介绍）

## 能量与采集

每个机器人具有一个能量值，双方的初始机器人各具有)V0G0N";
cout << "$" << baseEnergy << "$" << "(`baseEnergy`)" << R"V0G0N(的能量值。能量可以通过采集获得，用于自然消耗与施放技能等的消耗。

地图中每个格子具有一个能量系数（`ENERGY`），每个机器人每回合会自动采集身边不超过)V0G0N";
cout << "$" << GatherRange << "$" << "(`GatherRange`)" << R"V0G0N(的算术平方根距离的能量，在每个格子的采集量等于机器人的采集力与格子的能量系数的乘积。

然而，如果一个格子同时在多个机器人的采集范围内，则只有那些离格子最近的机器人会参与采集。这些格子的能量系数（`ENERGY`）会被最近的这些机器人均分。

### 分裂、进退化

每个玩家除了初始的机器人以外，还可以通过分裂（或其他方法，见后述）创造新的机器人。

每个机器人有一个等级，初始时为0。每个机器人每回合都会消耗一定量的能量，这个消耗量和机器人的各项战斗能力（生命值、攻击力等）均与等级成指数增长关系。具体计算方式见`stats.cpp`。

在自动消耗完成后，机器人会自动恢复)V0G0N";
cout << "$" << fromPercent(RecoveryHPRate) << "$" << "(`RecoveryHPRate`)" << R"V0G0N(的HP。如果某个机器人的能量不足其自动消耗量，则会本回合不会消耗能量，但会改为扣减)V0G0N";
cout << "$" << fromPercent(-WitherHPRate) << "$" << "(`-WitherHPRate`)" << R"V0G0N(的HP。

机器人可以消耗一定的能量进行进化，使自己的等级提升；或选择降低自己的等级，并获得一部分返还的能量。返还的能量为当初进化所消耗的能量的)V0G0N";
cout << "$" << fromPercent(VestigialLost) << "$" << "(`VestigialLost`)" << R"V0G0N(。

### 机器人类型与技能

机器人分为攻击型、防御型、采集型机器人和无类型机器人。每个机器人初始时无类型。

当机器人进化时，如果原来属于无类型机器人，玩家可以选择将其类型变为任意一种类型；否则不能改变。

当机器人退化时，即使机器人已经有了类型，玩家也可以将其转换为另一种类型。然而，当退化到0级时只能退化为无类型机器人。

游戏共有十多种技能，包括公共技能、攻击型技能、防御型技能、采集型技能。所有机器人都可以使用公共技能，但是其他技能只有该类型的机器人才能使用。

公共技能包括：普通攻击、分裂、进化、退化、建立连接、传输、删除连接。

攻击型技能包括：天灾、轰炸。

防御型技能包括：庇护、再生。

采集型技能包括：过载、空投。

## 单位属性

单位属性分为以下几种：

### 最大HP

* 名称： `max_hp`
* 效果：描述机器人的最大生命值
* 当类型为**防御型**时，最大HP是同等级其他机器人的2倍。

### 攻击力

* 名称： `attack`
* 效果：描述机器人的攻击威力
* 当类型为**攻击型**时，攻击力是同等级其他机器人的2倍。

### 防御力

* 名称： `defense`
* 效果：描述机器人的防御伤害的效果
* 当计算伤害时，机器人受到的实际伤害为 $[Attack\_Power] * \frac{defenseBaseValue}{defenseBaseValue + [defense]}$，并下取整。

### 采集效率
* 名称：`efficiency`
* 效果：描述机器人采集能量的效率
* 当类型为**采集型**时，采集效率是同等级其他类型机器人的两倍。

### 传输效率
* 名称：`capacity`
* 效果：描述机器人每回合最大的向外传输量
* 当类型为**采集型**时，传输效率是同等级其他类型机器人的两倍。

### 消耗
* 名称：`consumption`
* 效果：描述机器人每回合的固定能量消耗

### 升级所需要的能量总量
* 不显示的属性
* 实际升级或降级时， 以两个等级的能量总量之间的差值进行计算。

各项属性的公式均为$base*rlevel^{Exp}$，其中 $rlevel = level+$ )V0G0N";
cout << "$" << levelBias << "$" << "(`levelBias`)" << R"V0G0N(
。数值见下表:

|属性名|`maxhp`|`attack`|`defense`|`efficiency`|`capacity`|`consumption`|LevelUP Consumption|
|-|-|-|-|-|-|-|-|-|-|
|`base`|)V0G0N";
cout << "$" << BaseHP << "$" << R"V0G0N(|)V0G0N";
cout << "$" << BaseAttack << "$" << R"V0G0N(|)V0G0N";
cout << "$" << BaseDefense << "$" << R"V0G0N(|)V0G0N";
cout << "$" << BaseEfficiency << "$" << R"V0G0N(|)V0G0N";
cout << "$" << BaseEfficiency * 30 << "$" << R"V0G0N(|)V0G0N";
cout << "$" << BaseConsumption << "$" << R"V0G0N(|)V0G0N";
cout << "$" << BaseConsumption * 20 << "$" << R"V0G0N(|
|`Exp`|)V0G0N";
cout << "$" << HPExp << "$" << R"V0G0N(|)V0G0N";
cout << "$" << AttackExp << "$" << R"V0G0N(|)V0G0N";
cout << "$" << DefenseExp << "$" << R"V0G0N(|)V0G0N";
cout << "$" << EfficiencyExp << "$" << R"V0G0N(|)V0G0N";
cout << "$" << EfficiencyExp << "$" << R"V0G0N(|)V0G0N";
cout << "$" << ConsumptionExp << "$" << R"V0G0N(|)V0G0N";
cout << "$" << ConsumptionExp << "$" << R"V0G0N(|
)V0G0N";
for (int i = 0, j = 0; j <= 12; ++ j, i += (j / 3 + 1)){ cout << R"V0G0N(|)V0G0N";
cout << "$" << i << "$" << R"V0G0N(级属性|)V0G0N";
cout << "$" << stats::getMaxHP(i, RawRobot) << "$" << R"V0G0N(|)V0G0N";
cout << "$" << stats::getAttack(i, RawRobot) << "$" << R"V0G0N(|)V0G0N";
cout << "$" << stats::getDefense(i, RawRobot) << "$" << R"V0G0N(|)V0G0N";
cout << "$" << stats::getEfficiency(i, RawRobot) << "$" << R"V0G0N(|)V0G0N";
cout << "$" << stats::getCapacity(i, RawRobot) << "$" << R"V0G0N(|)V0G0N";
cout << "$" << stats::getConsumption(i) << "$" << R"V0G0N(|)V0G0N";
cout << "$" << stats::getLevelUPConsumption(i) << "$" << R"V0G0N(|
)V0G0N";
} cout << R"V0G0N(

**请尽可能不要使用硬编码的数值，应该使用`stats::getxxx`系列函数，如`stats::getMaxHP`。
否则我们的平衡性修改可能会对你的程序造成很大的影响**

## 游戏流程

### 回合结算流程

在每个回合内，双方依次行动，分别下达指令，然后统一进行计算。

不同玩家执行操作时若遇到冲突（比如同时在一个格子上建立机器人或者空投），按照“12211221……”的次序决定优先权，即：首回合玩家1优先，接下来的两回合玩家2优先，在接下来的两回合玩家1优先……注意这个回合数也包括了未产生冲突的回合。

回合结算的顺序按照以下的列表：

* 采集阶段（`ProduceTurn`），所有机器人采集养分
* 连接阶段（`LinkTurn`），所有机器人进行连接
* 传输阶段（`TransferTurn`），所有机器人传输能量
* 进退化阶段（`EvolveTurn`），所有机器人进行进化和退化
* 属性计算阶段（`StatsCalculationTurn`），进行一次属性重算
* 辅助技能阶段（`AuxiliaryTurn`），使用所有辅助类技能
* Buff技能阶段（`Buff`），结算所有Buff的效果
* 攻击阶段（`AttackTurn`），使用所有伤害和回复类技能
* 自动恢复阶段（`AutoRecoveryTurn`），进行自动恢复

### 胜负判定

若一方失去了所有的机器人，游戏结束，该方判负。若双方在同一回合失去了所有机器人，则判为平局。

若指定回合后没有分出胜负，将以场上机器人的总价值大小判断胜负。

一个机器人的价值，等于其能量与从0级进化到该机器人等级所需的能量之和。

## 公共技能

一个技能的冷却时间是指，连续两次使用该技能至少应等待的回合数。例如：冷却时间为2表示，至多每2回合可以使用一次这个技能；冷却时间为1表示，每回合都可以使用一次这个技能；冷却时间为0表示，每回合可以多次使用这个技能。

注意在编写AI时，由于所有机器人都可以使用公共技能（本节内所有技能），所以已经冷却完毕的**公共**技能可能不会出现在某个机器人的技能列表中。

对于所有技能，如果你使用SDK，且技能的参数需要传入某个机器人的`id`，只需要在SDK中传入其位置`pos`，SDK会自动将其转为`id`。

伤害类技能中会出现“几倍伤害”的字样，是指伤害值为技能施放者攻击力的几倍。这个数值还会根据受伤害者的防御力进行降低。

### 普通攻击

* 指令名称/技能名称：`PlainAttack`/`PlainAttackSkill`
* 消耗能量：无
* 冷却时间：1
* 参数：目标机器人的`id`
* 有效范围：使用者的`attack_range`的算术平方根
* 结算阶段：攻击阶段（`AttackTurn`）

效果：对目标机器人造成1倍伤害。

* 可以攻击己方的机器人。
* 攻击阶段中目标机器人不会立刻死亡，只有在之后的死亡结算阶段才会死亡。

### 分裂

* 指令名称/技能名称：`Split`/`SplitSkill`
* 消耗能量：)V0G0N";
cout << "$" << FixedSplitCost << "$" << "(`FixedSplitCost`)" << R"V0G0N(
* 冷却时间：0
* 参数：目标位置x，目标位置y
* 有效范围：)V0G0N";
cout << "$" << SplitRange << "$" << "(`SplitRange`)" << R"V0G0N(的算术平方根
* 结算阶段：辅助技能阶段（`AuxiliaryTurn`）

效果：在目标地点创建一个新的己方机器人，其初始能量值为)V0G0N";
cout << "$" << FixedSplitPower << "$" << "(`FixedSplitPower`)" << R"V0G0N(。

* 需要保证目标位置无机器人，且不是障碍物，否则分裂不成功。
* 同一机器人同一回合可在多个目标点分裂。@TODO:需要讨论
* 同一玩家同一回合多次分裂，按给出命令的次序依次结算。

### 进化

* 指令名称/技能名称：`Evolve`/`EvolveSkill`
* 消耗能量：`stats::getLevelUPConsumption(level + 1) - stats::getLevelUPConsumption(level)`，其中`level`为机器人的当前等级
* 冷却时间：0
* 参数：希望进化为的类型
* 结算阶段：进退化阶段（`EvolveTurn`）

效果：自身等级`level`提升1级，并变为目标的类型。如果是从无类型机器人变为有类型，则获得其类型的技能并重置其冷却时间。

* 无类型机器人可以进化为任何类型（或保持无类型），有类型机器人进化时只能保持原类型。如果给出的参数非法则进化无效。
* 同一机器人同一回合可多次进化。
* SDK中有简便的`Evolve`函数，能添加一个将某个机器人按原类型进化一级的指令。

### 退化

* 指令名称/技能名称：`Vestigial`/`VestigialSkill`
* 获得能量：`(stats::getLevelUPConsumption(level) - stats::getLevelUPConsumption(level-1)) * VestigialLost`，其中`level`为机器人的当前等级
* 冷却时间：0
* 参数：希望退化为的类型
* 结算阶段：进退化阶段（`EvolveTurn`）

效果：自身等级`level`降低1级，获得返还能量，其值为当初进化所需能量的)V0G0N";
cout << "$" << fromPercent(VestigialLost) << "$" << "(`VestigialLost`)" << R"V0G0N(，并变为目标的类型。如果类型发生了改变，则失去原类型的技能并获得新类型（如有）的技能。

* 如果退化到了0级，则只能退化为无类型机器人。如果给出的参数非法则退化无效。
* 同一机器人同一回合可多次退化。
* SDK中有简便的`Vestigial`函数，能添加一个将某个机器人按原类型退化一级的指令。

### 建立连接

* 指令名称/技能名称：`Connect`/`ConnectSkill`
* 消耗能量：无
* 冷却时间：0
* 参数：目标机器人的`id`
* 有效范围：)V0G0N";
cout << "$" << SplitRange << "$" << "(`SplitRange`)" << R"V0G0N(的算术平方根
* 结算阶段：连接阶段（`LinkTurn`）

效果：延迟*接下来的*)V0G0N";
cout << "$" << LinkBuildTime << "$" << "(`LinkBuildTime`)" << R"V0G0N(回合后，与目标机器人建立连接。连接是单向关系，使用者可以对其使用传输等技能。

* 建立连接不能使该机器人向外连接的总边数超过其`outdeg`属性。
* 可以与对方机器人建立连接。
* 同一机器人同一回合可同时与多个机器人开始建立连接。
* 连接的任何一方死亡，则连接断开。

### 传输

* 指令名称/技能名称：`Transfer`/`TransferSkill`
* 消耗能量：可变
* 冷却时间：0
* 参数：目标机器人的`id`，要传输的能量值
* 结算阶段：传输阶段（`TransferTurn`）


效果：自己消耗这些能量值，为对方加上这些能量值。使用者之前必须与目标建立过连接，否则无效。

* 向外传输的总能量值不能超过使用者的传输容量`transport_capacity`。
* 同一机器人同一回合可以向多个不同的机器人进行传输。
* 允许使用者的能量值小于要传输的能量值，只要使用者能在传输阶段结束之前获得（从其他机器人传输来的）能量，使自己最终的能量值非负即可。
* 如果出现了非法情况（某个机器人的能量在传输阶段结束时能量为负），则该机器人本回合使用的所有传输操作无效。选手在编写的时候不应该出现非法的情况，否则复杂连接下非法，**无效哪些传输**这件事是无法确定的。
* 可以传输给对方机器人。

### 删除连接

* 指令名称/技能名称：`Disconnect`/`DisconnectSkill`
* 消耗能量：无
* 冷却时间：0
* 参数：目标机器人的`id`
* 结算阶段：连接阶段（`LinkTurn`）

效果：（立即）删除与目标的连接。使用者之前必须与目标建立过连接，否则无效。

* 同一机器人同一回合可以删除与多个机器人的连接。

## 攻击型技能


### 轰炸
* 技能名称：`Bombing`
* 冷却时间：)V0G0N";
cout << "$" << BombingCD << "$" << "(`BombingCD`)" << R"V0G0N(
* 技能射程：)V0G0N";
cout << "$" << BombingRange << "$" << "(`BombingRange`)" << R"V0G0N(的算术平方根
* 覆盖范围：以目标位置为中心，半径为)V0G0N";
cout << "$" << BombingRadius << "$" << "(`BombingRadius`)" << R"V0G0N(的算术平方根的圆
* 参数：目标位置x，目标位置y
* 结算阶段：攻击阶段（`AttackTurn`）

效果：造成范围伤害，伤害值为普通攻击的)V0G0N";
cout << "$" << fromPercent(BombingDamage) << "$" << "(`BombingDamage`)" << R"V0G0N(。

### 天灾

* 技能名称：`Scourge`
* 冷却时间：)V0G0N";
cout << "$" << ScourgeCD << "$" << "(`ScourgeCD`)" << R"V0G0N(
* 技能射程：与普通攻击相同
* 参数：目标机器人的`id`
* 伤害：普通攻击的)V0G0N";
cout << "$" << fromPercent(ScourgeDamage) << "$" << "(`ScourgeDamage`)" << R"V0G0N(
* 结算阶段：攻击阶段（`AttackTurn`）

效果：对目标施加一个Debuff，每回合扣减相当于当前一次攻击伤害的血量。这个Debuff将会在目标所有连接的其他机器人上传递，但不会传递到已经具有这个Debuff的机器人上。当Debuff传递时，伤害值会按照血量传递，而无视防御值的影响。


## 防御型技能

### 再生

* 技能名称：`Recover`
* 冷却时间：)V0G0N";
cout << "$" << RecoverCD << "$" << "(`RecoverCD`)" << R"V0G0N(
* 参数：目标`id`
* 结算阶段：攻击阶段（`AttackTurn`）

效果：恢复目标相当于自身最大HP的)V0G0N";
cout << "$" << fromPercent(RecoverMaxHPRate) << "$" << "(`RecoverMaxHPRate`)" << R"V0G0N(的血量。

* 这个技能只能对自己或自己连接的目标释放。

### 庇护

* 技能名称：`Shielding`
* 冷却时间：)V0G0N";
cout << "$" << ShieldingCD << "$" << "(`ShieldingCD`)" << R"V0G0N(
* 参数：无
* 效果范围：以使用者为中心，半径为)V0G0N";
cout << "$" << ShieldingRadius << "$" << "(`ShieldingRadius`)" << R"V0G0N(的算术平方根的圆
* 结算阶段：辅助技能阶段（`AuxiliaryTurn`）

效果：庇护自身周围的单位。范围内的单位防御获得相当于自身防御力)V0G0N";
cout << "$" << fromPercent(DefenseShareRate) << "$" << "(`DefenseShareRate`)" << R"V0G0N(的加成，范围内的敌方单位攻击力为原来的)V0G0N";
cout << "$" << fromPercent(AttackRate) << "$" << "(`AttackRate`)" << R"V0G0N(。Buff或Debuff持续)V0G0N";
cout << "$" << ShieldingLast << "$" << "(`ShieldingLast`)" << R"V0G0N(回合


## 采集型技能

### 过载

* 技能名称：`Overload`
* 冷却时间：)V0G0N";
cout << "$" << OverloadCD << "$" << "(`OverloadCD`)" << R"V0G0N(
* 参数：无
* 结算阶段：辅助技能阶段（`AuxiliaryTurn`）

效果：暂时提升自己的采集能力。在)V0G0N";
cout << "$" << HighRank << "$" << "(`HighRank`)" << R"V0G0N(回合内获得`OverloadHighBuff`，采集和传输能力上升$100\%$。在之后的)V0G0N";
cout << "$" << LowRank << "$" << "(`LowRank`)" << R"V0G0N(回合内获得`OverloadLowBuff`，采集和传输能力下降$50\%$。

* 同一个Buff不能叠加，再次获得同样的Buff时，前一个Buff自动失效。
* 两个Buff可以同时持有，效果叠加。


### 空投

* 技能名称：`Airborne`
* 冷却时间：)V0G0N";
cout << "$" << AirborneCD << "$" << "(`AirborneCD`)" << R"V0G0N(
* 消耗能量：可变，至少为)V0G0N";
cout << "$" << FixedAirborneCost << "$" << "(`FixedAirborneCost`)" << R"V0G0N(
* 参数：目标位置，希望传递的能量值
* 结算阶段：辅助技能阶段（`AuxiliaryTurn`）
效果：消耗自己的能量，在指定位置产生一个机器人。消耗量为)V0G0N";
cout << "$" << FixedAirborneCost << "$" << "(`FixedAirborneCost`)" << R"V0G0N(加上你想要传递的能量值。你想要传递的能量值将会乘上)V0G0N";
cout << "$" << AirborneLost << "$" << "(`AirborneLost`)" << R"V0G0N(之后，在*接下来的*)V0G0N";
cout << "$" << AirborneTurn << "$" << "(`AirborneTurn`)" << R"V0G0N(回合内均匀地转移到该机器人身上。


* 该技能没有射程限制。

## SDK

SDK包含以下的文件：

### const.h

定义游戏中出现的所有常量

### sdk.h

包含了`PPlayerInfo.h`与`interpreter.h`。

### PPlayerInfo.h

定义了可以用于包含游戏内各种元素的类的接口，可以让你更方便地与逻辑进行交互。

其中，`SDK::PPlayerInfo`描述局面信息，`SDK::PCommand`描述玩家操作。

### interpreter.h

定义了sdk与逻辑接口的翻译函数，你只需要使用里面的函数即可。

## AI编写

AI的编写需要编写以下两个函数：

```cpp
void player_ai(const PlayerInfo &, Commands &, SDK::PShowInfo &)
```

这个函数完成AI的编写。其中，`PlayerInfo`描述玩家信息，`Commands`用来传递指令，`SDK::PShowInfo`用来传递给播放器一些额外信息。

```cpp
void feedback_ai(vector<HumanOrder>, PShowInfo &)
```

播放器每一帧都会调用这个函数，以完成人能实时给AI提示的功能。该函数应当解析输入的人类指令`vector<HumanOrder>`，处理后修改`PShowInfo`。注意，`feedback_ai`与`player_ai`是由两个程序调用的，不能共享地址空间（例如全局变量的值），你只能通过`PShowInfo `来进行两个函数间的交互。

你可以使用SDK来操作AI的编写，一个范例的程序如下

```cpp
PPlayerInfo playerInfo;
PCommand pCommand;
PShowInfo *pShowInfo;
void player_ai(const PlayerInfo &playerInfo_, Commands &pCommand_, SDK::PShowInfo &pShowInfo_) {
	//翻译PlayerInfo
	playerInfo = SDK::interpretPlayerInfo(playerInfo_);
	/**
	* 此处加入AI代码
	*/
	//根据你的一些需求添加自动传输
	pCommand.AddAutoTransfer(playerInfo, weights, needs);
    //翻译Commands
    pCommand_ = SDK::translateCommands(playerInfo, pCommand);
    pCommand.cmds.clear();
}

```

以下是AI的编写提供的其他内部接口，你可以自由选择使用它们：

* `PlayerInfo.h`：定义获得的指令。`PlayerInfo`类包含两个成员`status`与`push_data`，分别代表内容的
* `Commands.h`：定义下达的指令，用于与逻辑交互。包含类`Commands`和类`Command`。
* `misc.h`：定义一些常用函数。
* `point.h`：一个用于定义二维平面点的常用接口。

## FAQ

* Q: 如何编译逻辑？
* A: 你需要把SDK中所有包含的cpp文件加入文件。对于支持Unix Make的工具链，你可以使用附带的Makefile进行编译。直接输入`make`或`mingw32-make`即可完成编译。你也可以自己建立Visual Studio工程、CMake项目或是采用其他方法编译。
* Q: 需要使用什么编译器？
* A: 需要使用具有完整C++11支持的编译器。Windows下的MinGW工具链推荐使用TDM-GCC。
* Q: api_test是什么？
* A: 是附带的简单的逻辑运行器。使用 `api_test <ai1> <ai2> <回合数> [可选 <随机种子>]`即可对指定的AI运行逻辑。
* Q: 为什么播放器无法在 Human Mode 下使用我的AI
* A: 你没有编写`feedback_ai`。
* Q: 逻辑崩溃/闪退了，如何检查错误。
* A: 请检查工作目录下`logic_err_log.txt`文件。
* Q: 附带AI乱码
* A: 请用支持UTF-8的编辑器打开
* Q: `logic_err_log.txt` 中出现 `no dll`错误
* A: 常见错误代码： `193` 平台不匹配，请确认你是否混用了32位/64位的文件。
* Q: `logic_err_log.txt` 中出现 `no ai`错误
* A: 常见错误代码： `127` 你的DLL中无法找到AI对应的函数。请检查你的函数名，是否被`extern "C"`，使用MSVC时是否被设置DLL导出（`__declspec(dllexport)`）。
)V0G0N" << endl;
}
